package com.cea.papyrus.diagram.classdiagram.commands;

import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.ClassifierTemplateParameter;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.TemplateParameter;

import com.cea.papyrus.core.commands.PapyrusCommand;

public class ElementReferencedByATemplateParameterCreateCommand extends PapyrusCommand {

	public final static int PARAMETERED_ELEMENT = 0 ;
	public final static int DEFAULT = 1 ;
	public final static int CONSTRAINING_CLASSIFIER = 2 ;
	
	/**
	 * Referenced element.
	 */
	private Element referencedElement;
	
	/**
	 * parent of the created element.
	 */
	private TemplateParameter umlParentTemplateParameter ;
	
	/**
	 * an int representing the property subset of TemplateParameter.ownedElements()
	 * must be equal to OWNED_PARAMETERED_ELEMENT or OWNED_DEFAULT
	 */
	private int elementPropertyKind ;
	
	
	public ElementReferencedByATemplateParameterCreateCommand(Element element, Class elementClass, TemplateParameter umlParent, int ownedElementPropertyKind) {
		super(elementClass) ; // this statement is useless
		this.umlParentTemplateParameter = umlParent ;
		this.elementPropertyKind = ownedElementPropertyKind ;
		this.referencedElement = element ;
		
		switch (this.elementPropertyKind) {
		case PARAMETERED_ELEMENT:
//			super.setLabel("Creation of an owned parametered " + elementMetaClass.getName()) ;
			break ;
		case DEFAULT:
//			super.setLabel("Creation of an owned default " + elementMetaClass.getName()) ;
			break ;
		case CONSTRAINING_CLASSIFIER:
			super.setLabel("Creation of a contraining classifier") ;
			break ;
		default:
			break;
		}
	}
	
	public void execute() {
		switch (elementPropertyKind) {
		case PARAMETERED_ELEMENT:
			umlParentTemplateParameter.setParameteredElement((ParameterableElement)referencedElement) ;
			((ParameterableElement)referencedElement).setTemplateParameter(umlParentTemplateParameter) ;
			break;
		case DEFAULT:
			umlParentTemplateParameter.setDefault((ParameterableElement)referencedElement) ;
			if (umlParentTemplateParameter instanceof ClassifierTemplateParameter)
				((ClassifierTemplateParameter)umlParentTemplateParameter).setDefaultClassifier((Classifier)referencedElement) ;
			break;
		case CONSTRAINING_CLASSIFIER:
			((ClassifierTemplateParameter)umlParentTemplateParameter).setConstrainingClassifier((Classifier)referencedElement) ;
			break;
		default:
			break;
		}
	}
	
	public boolean canExecute() {
		return umlParentTemplateParameter instanceof TemplateParameter ; 
	}
	
	public void redo() {
//		switch (this.elementPropertyKind) {
//		case PARAMETERED_ELEMENT:
//			umlParentTemplateParameter.setParameteredElement((ParameterableElement)referencedElement) ;
//			break;
//		case DEFAULT:
//			umlParentTemplateParameter.setDefault((ParameterableElement)referencedElement) ;
//			if (umlParentTemplateParameter instanceof ClassifierTemplateParameter) {
//				((ClassifierTemplateParameter)umlParentTemplateParameter).setDefaultClassifier((Classifier)referencedElement) ;
//			}
//			break;
//		case CONSTRAINING_CLASSIFIER:
//			((ClassifierTemplateParameter)umlParentTemplateParameter).setConstrainingClassifier((Classifier)referencedElement) ;
//			break;
//		default:
//			break;
//		}
		execute() ;
	}
	
	public void undo() {
		switch (this.elementPropertyKind) {
		case PARAMETERED_ELEMENT:
			umlParentTemplateParameter.setParameteredElement(null) ;
			((ParameterableElement)referencedElement).setTemplateParameter(null) ;
			break;
		case DEFAULT:
			umlParentTemplateParameter.setDefault(null) ;
			if (umlParentTemplateParameter instanceof ClassifierTemplateParameter)
				((ClassifierTemplateParameter)umlParentTemplateParameter).setDefaultClassifier(null) ;
			break;
		case CONSTRAINING_CLASSIFIER:
			((ClassifierTemplateParameter)umlParentTemplateParameter).setConstrainingClassifier(null) ;
			break;
		default:
			break;
		}
	}
	
	public boolean canUndo() {
		return referencedElement != null ;
	}
	
	public boolean canRedo() {
		return referencedElement != null ;
	}
}
